// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... namespace LargoCommon.Music { using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; /// /// Harmonic Stream Analyzer. /// public class HarmonicStreamAnalyzer { #region Fields /// /// Maximum number of Tones In Chord. /// private readonly byte maxTonesInChord; /// /// Full Harmonization. /// private readonly bool fullHarmonization; /// /// The header /// private readonly MusicalHeader header; /// /// Last harmonic structure. /// private HarmonicStructure lastHarmonicStructure; /// /// The first tick. /// private byte firstTick; #endregion #region Constructors /// /// Initializes a new instance of the class. /// /// The given header. /// The given max tones in chord. /// If set to true [given full harmonization]. public HarmonicStreamAnalyzer(MusicalHeader givenHeader, byte givenMaxTonesInChord, bool givenFullHarmonization) { this.header = givenHeader; this.maxTonesInChord = givenMaxTonesInChord; this.fullHarmonization = givenFullHarmonization; } #endregion #region Properties /// /// Gets or sets Harmonic Space. /// public HarmonicSpace HarmonicSpace { get; set; } /// /// Gets or sets a value indicating whether Sharp Chord Edges. /// public bool SharpChordEdges { get; set; } #endregion #region String representation /// String representation of the object. /// Returns value. public override string ToString() { return $"HarmonicStreamAnalyzer (SharpChordEdges {this.SharpChordEdges})"; } #endregion #region Public methods /// /// Determine Harmony In Bar. /// /// The given bar. /// /// Returns value. /// public HarmonicBar DetermineHarmonyInBar(MusicalBar givenBar) { var sourceTones = givenBar.MelodicTonesAround(6, 6); var harmonicModality = new HarmonicModality(this.header.System.HarmonicOrder, sourceTones, 0, false); var barTones = givenBar.MelodicTones; if (barTones == null) { return null; } HarmonicBar harmonicBar; var musicalTones = barTones; if (!musicalTones.Any()) { harmonicBar = HarmonicBar.EmptyBar(this.header.System.HarmonicOrder, this.header.System.RhythmicOrder); harmonicBar.BarNumber = 1; //// 2016/08 givenBar.BarNumber; //// 2016/08 ?! return harmonicBar; } var rsystem = this.header.System.RhythmicSystem; var rorder = this.header.System.RhythmicOrder; var barMetric = new BinaryStructure(rsystem, 0); //// barMetric.On(0); harmonicBar = new HarmonicBar(0, givenBar.BarNumber) { Header = givenBar.Body.Context.Header }; this.lastHarmonicStructure = null; //// int length; this.firstTick = 0; this.HarmonicSpace.Reset(harmonicModality); for (byte tick = 0; tick < rorder; tick++) { var br = new BitRange(rorder, tick, 1); var tonesAtTick = new MusicalToneCollection(musicalTones, br, false); this.AnalyzeHarmonyAtTick(harmonicBar, tick, tonesAtTick, barMetric); } if (this.firstTick < this.header.System.RhythmicOrder) { var harmonicStructure = this.HarmonicSpace.DetermineHarmonicStructure(this.maxTonesInChord, this.fullHarmonization); if (harmonicStructure != null) { this.ResolveStructure(harmonicBar, barMetric, harmonicStructure, this.header.System.RhythmicOrder); } } barMetric.DetermineLevel(); var barMetricCode = barMetric.GetStructuralCode; harmonicBar.SetBarMetricCode(barMetricCode); harmonicBar.SetHarmonicModalityCode(harmonicModality.GetStructuralCode); return harmonicBar; } #endregion #region Public methods /// /// Analyzes the harmony at tick. /// /// The harmonic motive bar. /// The tick. /// The melodic tones. /// The bar metric. private void AnalyzeHarmonyAtTick(HarmonicBar harmonicBar, byte givenTick, ICollection givenTones, BinaryStructure barMetric) { Contract.Requires(givenTones != null); var tick = givenTick; var anyStartAtThisTick = givenTones.Count > 0 && (from dt in givenTones where dt.BitFrom == tick select 1).Any(); if (anyStartAtThisTick && tick > 0) { var harmonicStructure = this.HarmonicSpace.DetermineHarmonicStructure(this.maxTonesInChord, this.fullHarmonization); if (harmonicStructure != null) { //// var harSystem = harmonicStructure.HarmonicSystem; //// HarmonicSystem.GetHarmonicSystem(this.SysOrder); //// var modality = new HarmonicModality(harSystem, 1387); ////201508 harmonicStructure = DataLink.BridgeHarmony.CompleteHarmonicStructure(harSystem, modality, harmonicStructure.GetStructuralCode()); //// harmonicStructure.DetermineBehavior(); this.ResolveStructure(harmonicBar, barMetric, harmonicStructure, tick); this.firstTick = tick; if (this.SharpChordEdges) { this.HarmonicSpace.Forget(); //// this.HarmonicSpace.Reset(harmonicModality); } } } else { barMetric.Off(tick); } if (givenTones.Count > 0) { this.HarmonicSpace.AcceptTonesOfTheTick(givenTones); } } /// /// Resolves the structure. /// /// The harmonic motive bar. /// The bar metric. /// The harmonic structure. /// The given tick. private void ResolveStructure(HarmonicBar harmonicBar, BinaryStructure barMetric, HarmonicStructure harmonicStructure, byte tick) { Contract.Requires(barMetric != null); Contract.Requires(harmonicStructure != null); var extendPrevious = (this.lastHarmonicStructure != null) && (string.CompareOrdinal(harmonicStructure.ElementSchema, this.lastHarmonicStructure.ElementSchema) == 0); if (extendPrevious) { barMetric.Off(this.firstTick); this.lastHarmonicStructure.Length = (byte)(this.lastHarmonicStructure.Length + tick - this.firstTick); } else { barMetric.On(this.firstTick); harmonicStructure.BitFrom = this.firstTick; var length = tick - this.firstTick; harmonicStructure.Length = (byte)length; harmonicBar.AddStructure(harmonicStructure); this.lastHarmonicStructure = harmonicStructure; } } #endregion } }